#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
#include <math.h>
#include <set>
#include <map>
#include <omp.h>
#include <algorithm>

using namespace std;


static int num_char = 5;

set <string> dici;
map <int, int> histo;
//pair< set<int>::iterator, bool > ret;

// Deixa as letras todas minusculas de uma string 
string toLowerCase(string s) {
    for (int i = 0; i < s.size(); i++)
        s[i] = tolower(s[i]);
    return s;
}

// Limpa a string de apontuacao
void remove_pontuacion(string& in) {
    for (int i = 0; i < in.length(); i++) {
        // ispunct é uma funcao da ctype.h que detecta se é alguma potuacao ja predefinida  
        if (in[i] < 97 || in[i] > 122 || ispunct(in[i]))
            in[i] = ' '; // troca a pontuacao por espaco em branco
    }
    return;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Quebra

/* Esta função quebra uma palavra com tamanho maior 
 * que 5 em palavras com tamanho 5 ou menor
*/ 
string quebra(string& in) {
	string out;
	
	for(int i = 0; i < in.size(); i++) {
		out += in[i];
		if( (i+1) % 4 == 0 ) out += " ";  
	}

	return out;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// TOKEN QUEBRA A STRING LINHA EM STRINGS MENORES, SEPARADAS POR ESPAÇO, SOMENTE PALAVRAS

// Dado uma linha do arquivo (in), quebra em palavras (palavras entre os espacos brancos)
// E verifica se é palindromo ou nao, se for verifica se é primo tambem.
void token(string& in) {
    istringstream iss(in);

    do {
        string sub;
        iss >> sub;

        if(sub.size() < 2) continue; 

        if( sub.size() > num_char )  {
        	istringstream iss_sub(quebra(sub));
        	
        	do {
        		string sub2;
        		iss_sub >> sub2;
        		sub2 = toLowerCase(sub2); // tudo caixa baixa 
          
            if( sub2.size() >= 2  && dici.insert( sub2 ).second ) histo[sub2.size()]++; //insere no dicionario
          
          } while(iss_sub);

        } else {
		      sub = toLowerCase(sub); // tudo caixa baixa
	        if( dici.insert( sub ).second ) histo[sub.size()]++; // insere no dicionario a palavra
          
	    }
    } while (iss); //ate as palavras acabarem
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Monta

/* Esta função pega todas as palavras que não são separadas por espaço 
 * presentes no texto e insere num set de strings chamado dici
*/
void monta(){
    string s;						//Declara variavel s, que receberá as linhas lidas do texto
    
    ifstream fin ("palavras.txt"); 			//Declara um arquivo e especifica qual arquivo deve ser aberto

    if (fin.is_open()){					//verifica se oarquivo está aberto
      while ( !fin.eof() ) { 				//Percorre o arquivo até chegar ao fim
          getline (fin,s, '\n'); 			//Lê linha do texto do arquivo
          //cout << s << endl;
    		  remove_pontuacion(s);
    		  token(s);	
    	}
    }
    //sort(dici.begin(), dici.end());			//ordena o vetor dici
    fin.close();
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// PALAVRA

/* Esta função gera aleatóriamente um conjunto de 2 caracteres
*/
string palavra(){
      string out;
      char ale;
      int tam;
                // 0 1 2 3
      tam = (int)rand()%(num_char-1) + 2;			//gera tamanho dapalavra aleatóriamente entre 2 e num_char

      if(!histo[tam]) return out;

      //Monta a palavra
      for(int i=0; i<tam; i++){
     	  ale = (int)rand()% 26 + 97;		//gera letra aleatória
      	out += ale;     				//insere letra aleatória no vetor
      }
      
      return out;					//retorna a string
} 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//Is_word

/* Esta função recebe uma string e verifica se está no dici
*/

bool is_word(string s){
	
	if(binary_search(dici.begin(),dici.end(), s)){return true;}	//retorna um se encontrou a string
	else{return false;}						//retorna 0  se não encontrou a string no vetor
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////




//Main 
int main(){
	string s;	
	
	monta();					    //le o texto e monta set dici
	srand(0);					    //libera semente para o random

	int k;

  cout << "total  " << dici.size() << endl;
  map<int, int>::iterator it;
  for(it=histo.begin(); it!=histo.end(); it++) {
    cout << "palavra de " << it->first << " chars: " << it->second << endl;
  }


	while( !dici.empty() ){
		
		s = palavra();
   // if(s.size() == 5) cout << s << endl;
    if(s.empty()) continue; 
		
		if(is_word(s)){				     //verifica se a palavra está no texto
		    histo[s.size()]--;
        cout <<"É palavra: "<< s;
  			dici.erase(s);
  			cout <<"  num:  "<< dici.size(); 
  			cout << endl; 
		}

    

		s.clear();				     //limpa string para receber nova palavra
	}

  /*cout << "bug: " << endl;
    set<string>::iterator it2;
    for(it2 = dici.begin(); it2!=dici.end(); it2++) {
      cout << *it2 << endl;
    }*/    
	return 0;
}